Merged [13563]: Localozed error strings when downloading xtras. Added exception handl...
[adiumx.git] / Plugins / URL Handling / XtrasInstaller.m
blobc91eda049d812ed91000289dd89efbc92212a835
1 /* 
2  * Adium is the legal property of its developers, whose names are listed in the copyright file included
3  * with this source distribution.
4  * 
5  * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
6  * General Public License as published by the Free Software Foundation; either version 2 of the License,
7  * or (at your option) any later version.
8  * 
9  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
10  * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
11  * Public License for more details.
12  * 
13  * You should have received a copy of the GNU General Public License along with this program; if not,
14  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
15  */
17 #import "XtrasInstaller.h"
18 #import <AIUtilities/CBApplicationAdditions.h>
19 #import <AIUtilities/ESBundleAdditions.h>
20 #import <AIUtilities/AIExceptionHandlingUtilities.h>
21 #import "NSString_UUID.h"
23 //Should only be YES for testing
24 #define ALLOW_UNTRUSTED_XTRAS   NO
26 @interface XtrasInstaller (PRIVATE)
27 - (void)closeInstaller;
28 @end
30 /*!
31  * @class XtrasInstaller
32  * @brief Class which displays a progress window and downloads an AdiumXtra, decompresses it, and installs it.
33  */
34 @implementation XtrasInstaller
36 //XtrasInstaller does not autorelease because it will release itself when closed
37 + (XtrasInstaller *)installer
39         return [[XtrasInstaller alloc] init];
42 - (id)init
44         if ((self = [super init])) {
45                 download = nil;
46                 window = nil;
47         }
48         
49         if(![NSApp isURLLoadingAvailable]) { 
50                 self = nil;  
51         } 
53         return self;
56 - (void)dealloc
58         [download release];
60         [super dealloc];
63 - (IBAction)cancel:(id)sender;
65         if (download) [download cancel];
66         [self closeInstaller];
69 - (void)sheetDidDismiss:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
71         [self cancel:nil];
74 - (void)closeInstaller
76         if (window) [window close];
77         [self autorelease];     
80 - (void)installXtraAtURL:(NSURL *)url
82         if ([[url host] isEqualToString:@"www.adiumxtras.com"] || ALLOW_UNTRUSTED_XTRAS) {
83                 NSURL   *urlToDownload;
85                 [NSBundle loadNibNamed:@"XtraProgressWindow" owner:self];
86                 [progressBar setUsesThreadedAnimation:YES];
87                 
88                 [progressBar setDoubleValue:0];
89                 [percentText setStringValue:@"0%"];
90                 [cancelButton setLocalizedString:AILocalizedString(@"Cancel",nil)];
91                 [window setTitle:AILocalizedString(@"Xtra Download",nil)];
92                 [window makeKeyAndOrderFront:self];
94                 urlToDownload = [[NSURL alloc] initWithString:[NSString stringWithFormat:@"%@://%@/%@?%@", @"http", [url host], [url path], [url query]]];
95 //              dest = [NSTemporaryDirectory() stringByAppendingPathComponent:[[urlToDownload path] lastPathComponent]];
97                 Class NSURLDownloadClass = NSClassFromString(@"NSURLDownload"); 
98                 Class NSURLRequestClass = NSClassFromString(@"NSURLRequest");    
99                 download = [[NSURLDownloadClass alloc] initWithRequest:[NSURLRequestClass requestWithURL:urlToDownload] delegate:self]; 
100 //              [download setDestination:dest allowOverwrite:YES];
102                 [urlToDownload release];
104         } else {
105                 NSRunAlertPanel(AILocalizedString(@"Nontrusted Xtra", nil),
106                                                 AILocalizedString(@"This Xtra is not hosted by adiumxtras.com. Automatic installation is not allowed.", nil),
107                                                 AILocalizedString(@"Cancel", nil),
108                                                 nil, nil);
109                 [self closeInstaller];
110         }
113 - (void)download:(NSURLDownload *)connection didReceiveResponse:(NSURLResponse *)response
115         amountDownloaded = 0;
116         downloadSize = [response expectedContentLength];
117         [progressBar setMaxValue:(long long)downloadSize];
118         [progressBar setDoubleValue:0.0];
121 - (void)download:(NSURLDownload *)connection decideDestinationWithSuggestedFilename:(NSString *)filename
123         NSString * downloadDir = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString uuid]];
124         [[NSFileManager defaultManager] createDirectoryAtPath:downloadDir attributes:nil];
125         dest = [downloadDir stringByAppendingPathComponent:filename];
126         [download setDestination:dest allowOverwrite:YES];
129 - (void)download:(NSURLDownload *)download didReceiveDataOfLength:(unsigned)length
131         amountDownloaded += (long long)length;
132         if (downloadSize != NSURLResponseUnknownLength) {
133                 [progressBar setDoubleValue:(double)amountDownloaded];
134                 [percentText setStringValue:[NSString stringWithFormat:@"%f%",(double)((amountDownloaded / (double)downloadSize) * 100)]];
135         }
136         else
137                 [progressBar setIndeterminate:YES];
140 - (BOOL)download:(NSURLDownload *)download shouldDecodeSourceDataOfMIMEType:(NSString *)encodingType {
141     return NO;
144 - (void)download:(NSURLDownload *)inDownload didFailWithError:(NSError *)error {
145         NSString        *errorMsg;
147         errorMsg = [NSString stringWithFormat:AILocalizedString(@"An error occurred while downloading this Xtra: %@.",nil),[error localizedDescription]];
148         
149         NSBeginAlertSheet(AILocalizedString(@"Xtra Downloading Error",nil), AILocalizedString(@"Cancel",nil), nil, nil, window, self,
150                                          NULL, @selector(sheetDidDismiss:returnCode:contextInfo:), nil, errorMsg);
153 - (void)downloadDidFinish:(NSURLDownload *)download {
154         NSArray                 *fileNames = nil;
155         NSString                *lastPathComponent = [[dest lowercaseString] lastPathComponent];
156         NSString                *pathExtension = [lastPathComponent pathExtension];
157         BOOL                    decompressionSuccess = YES;
158         
159         if ([pathExtension isEqualToString:@"tgz"] || [lastPathComponent hasSuffix:@".tar.gz"]) {
160                 NSTask                  *uncompress, *untar;
161                 
162                 uncompress = [[NSTask alloc] init];
163                 [uncompress setLaunchPath:@"/usr/bin/gunzip"];
164                 [uncompress setArguments:[NSArray arrayWithObjects:@"-df" , [dest lastPathComponent] ,  nil]];
165                 [uncompress setCurrentDirectoryPath:[dest stringByDeletingLastPathComponent]];
166                 
167                 AI_DURING
168                 {
169                 [uncompress launch];
170                 [uncompress waitUntilExit];
171                 }
172                 AI_HANDLER
173                 {
174                         decompressionSuccess = NO;      
175                 }
176                 AI_ENDHANDLER
177                         
178                 [uncompress release];
179                 
180                 if (decompressionSuccess) {
181                         if ([pathExtension isEqualToString:@"tgz"]) {
182                                 dest = [[dest stringByDeletingPathExtension] stringByAppendingPathExtension:@"tar"];
183                         } else {
184                                 //hasSuffix .tar.gz
185                                 dest = [dest substringToIndex:[dest length] - 3];//remove the .gz, leaving us with .tar
186                         }
187                         
188                         untar = [[NSTask alloc] init];
189                         [untar setLaunchPath:@"/usr/bin/tar"];
190                         [untar setArguments:[NSArray arrayWithObjects:@"-xvf", [dest lastPathComponent], nil]];
191                         [untar setCurrentDirectoryPath:[dest stringByDeletingLastPathComponent]];
192                         
193                         AI_DURING
194                         {
195                         [untar launch];
196                         [untar waitUntilExit];
197                         }
198                         AI_HANDLER
199                         {
200                                 decompressionSuccess = NO;
201                         }
202                         AI_ENDHANDLER
203                         [untar release];
204                 }
205                 
206         } else if ([pathExtension isEqualToString:@"zip"]) {
207                 NSTask  *unzip;
208                 
209                 //First, perform the actual unzipping
210                 unzip = [[NSTask alloc] init];
211                 [unzip setLaunchPath:@"/usr/bin/unzip"];
212                 [unzip setArguments:[NSArray arrayWithObjects:
213                         @"-o",  /* overwrite */
214                         @"-q", /* quiet! */
215                         dest, /* source zip file */
216                         @"-d", [dest stringByDeletingLastPathComponent], /*destination folder*/
217                         nil]];
218                 
219                 [unzip setCurrentDirectoryPath:[dest stringByDeletingLastPathComponent]];
220                 
221                 AI_DURING
222                 {
223                         [unzip launch];
224                         [unzip waitUntilExit];
225                 }
226                 AI_HANDLER
227                 {
228                         decompressionSuccess = NO;                      
229                 }
230                 AI_ENDHANDLER
231                 [unzip release];
233         } else {
234                 decompressionSuccess = NO;
235         }
236         
237         NSFileManager * fileManager = [NSFileManager defaultManager];
238         //Delete the compressed xtra, now that we've decompressed it
239         [fileManager removeFileAtPath:dest handler:nil];
240         
241         dest = [dest stringByDeletingLastPathComponent];
242         
243         //the remaining files in the directory should be the contents of the xtra
244         fileNames = [fileManager directoryContentsAtPath:dest];
245         AILog(@"Downloaded to %@. fileNames: %@",dest,fileNames);
246         
247         if (decompressionSuccess && fileNames) {
248                 NSEnumerator    *fileEnumerator;
249                 NSString                *xtraPath;
250                 NSString                *nextFile;
251                 NSSet                   *supportedDocumentExtensions = [[NSBundle mainBundle] supportedDocumentExtensions];
252                 
253                 fileEnumerator = [fileNames objectEnumerator];
254                 while((nextFile = [fileEnumerator nextObject]))
255                 {
256                         NSString                *fileExtension = [nextFile pathExtension];
257                         NSEnumerator    *supportedDocumentExtensionsEnumerator;
258                         NSString                *extension;
259                         BOOL                    isSupported = NO;
260                         
261                         //We want to do a case-insensitive path extension comparison
262                         supportedDocumentExtensionsEnumerator = [supportedDocumentExtensions objectEnumerator];
263                         while (!isSupported &&
264                                    (extension = [supportedDocumentExtensionsEnumerator nextObject])) {
265                                 isSupported = ([fileExtension caseInsensitiveCompare:extension] == NSOrderedSame);
266                         }
267                         
268                         if (isSupported) {
269                                 BOOL    success;
270                                 
271                                 xtraPath = [dest stringByAppendingPathComponent:nextFile];
272                                 
273                                 //Open the file directly
274                                 AILog(@"Installing %@",xtraPath);
275                                 success = [[NSApp delegate] application:NSApp
276                                                                                    openTempFile:xtraPath];
277                                 
278                                 if (!success) {
279                                         NSLog(@"Installation Error: %@",xtraPath);
280                                 }
281                         }
282                 }
283                 
284         } else {
285                 NSLog(@"Installation Error: %@ (%@)",dest, (decompressionSuccess ? @"Decompressed succesfully" : @"Failed to decompress"));
286         }
287         
288         //delete our temporary directory, and any files remaining in it
289         [fileManager removeFileAtPath:[dest stringByDeletingLastPathComponent] handler:nil];
290         
291         [self closeInstaller];
294 @end